/* Archive Extractor
 * Copyright 2008-2009 Matthew Hoops
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $URL: http://archive-extractor.googlecode.com/svn/trunk/iso_image.cpp $
 * $Id: iso_image.cpp 2 2009-03-23 01:29:43Z clone2727 $
 *
 */

#include "iso_image.h"

IsoDiscImage::IsoDiscImage() : StandardArchive() {
}

std::vector<const char*> IsoDiscImage::getArchiveExtensions() {
	std::vector<const char*> exList;
	exList.push_back("iso");
	// TODO: Other extensions!
	return exList;
}

int IsoDiscImage::detect(FILE* file) {
	fseek(file, 0x8001, SEEK_SET);
	static const byte magic[5] = { 'C', 'D', '0', '0', '1' };
	for (byte i = 0; i < 5; i++)
		if (readByte(file) != magic[i])
			return 0;
	return 100;
}

// 723 means LE then BE (uint16)
// 731 means LE (uint32)
// 732 means BE (uint32)
// 733 means LE then BE (uint32)

struct IsoDirectoryRecord {
	byte length;
	byte ext_attr_length;
	uint32 extent; // 733
	uint32 size; // 733
	unsigned char date[7];
	byte flags;
	byte file_unit_size;
	byte interleave;
	uint16 volume_sequence_number; // 723
	byte name_len;
	unsigned char name[38];
};

struct IsoDateAndTime {
	uint32 year; //char year[4];
	uint16 month; //char month[2];
	uint16 day; //char day[2];
	uint16 hour; //char hour[2];
	uint16 minute; //char minute[2];
	uint16 second; //char second[2];
	uint16 hundredths_of_a_second; //char hundredths_of_a_second[2];
	int8 utc_offset;
};

struct IsoPrimaryDescriptor {
	byte type;
	unsigned char id[5];
	byte version;
	byte unused1;
	unsigned char system_id[32]; // a-unsigned chars
	unsigned char volume_id[32]; // d-unsigned chars
	byte unused2[8];
	uint32 volume_space_size; // 733
	byte unused3[32];
	uint16 volume_set_size; // 723
	uint16 volume_sequence_number; // 723
	uint16 logical_block_size; // 723
	uint32 path_table_size; // 733
	uint32 type_l_path_table; // 731
	uint32 opt_type_l_path_table; // 731
	uint32 type_m_path_table; // 732
	uint32 opt_type_m_path_table; // 732
	IsoDirectoryRecord root_directory_record;
	unsigned char volume_set_id[128]; // d-unsigned chars
	char publisher_id[128]; // a-chars
	char preparer_id[128]; // a-chars
	char application_id[128]; // a-chars
	char copyright_file_id[37]; // d-chars (???)
	char abstract_file_id[37]; // d-chars (???)
	char bibliographic_file_id[37]; // d-chars (???)
	IsoDateAndTime creation_date;
	IsoDateAndTime modification_date;
	IsoDateAndTime expiration_date;
	IsoDateAndTime effective_date;
	byte file_structure_version;
	byte unused4;
	byte application_date[512];
	byte unused5[653];
};

static uint16 read723(FILE* file) {
	uint16 leNum = readUint16LE(file);
	uint16 beNum = readUint16BE(file);
	if (leNum != beNum)
		printf ("ERROR: Bad ISO 9660 723 data!\n");
	return leNum;
}

static uint32 read733(FILE* file) {
	uint32 leNum = readUint32LE(file);
	uint32 beNum = readUint32BE(file);
	if (leNum != beNum)
		printf ("ERROR: Bad ISO 9660 733 data!\n");
	return leNum;
}

static IsoDirectoryRecord readDirectoryRecord(FILE* file) {
	IsoDirectoryRecord rec;
	
	rec.length = readByte(file);
	rec.ext_attr_length = readByte(file);
	rec.extent = read733(file);
	rec.size = read733(file);
	fread(rec.date, 1, 7, file);
	rec.flags = readByte(file);
	rec.file_unit_size = readByte(file);
	rec.interleave = readByte(file);
	rec.volume_sequence_number = read723(file);
	rec.name_len = readByte(file);
	fread(rec.name, 1, 38, file);
	
	return rec;
}

#define READ_UINT32_STR(x) \
	fread(buffer, 1, 4, file); \
	x = buffer[0] * 1000 + buffer[1] * 100 + buffer[2] * 10 + buffer[3];
	
#define READ_UINT16_STR(x) \
	fread(buffer, 1, 2, file); \
	x = buffer[0] * 10 + buffer[1];

static IsoDateAndTime readDateAndTime(FILE* file) {
	IsoDateAndTime dt;
	char buffer[4];
	
	READ_UINT32_STR(dt.year);
	READ_UINT16_STR(dt.month);
	READ_UINT16_STR(dt.day);
	READ_UINT16_STR(dt.hour);
	READ_UINT16_STR(dt.minute);
	READ_UINT16_STR(dt.second);
	READ_UINT16_STR(dt.hundredths_of_a_second);
	dt.utc_offset = readSint8(file);
	
	return dt;
}

bool IsoDiscImage::extractFiles(FILE* file) {
	fseek(file, 0x8000, SEEK_SET);
	return false;
}
